/*
 * Orchard Core中实现了基于角色的访问控制，建议用于授权。有不同的角色，每个角色都有一组权限
 * （例如查看特定内容、编辑内容或访问管理面板）。当您想要授权用户时，您必须使用IAuthorizationService
 * 来检查当前用户是否具有您作为参数提供的权限（即用户是否在具有给定权限的角色中）。
 * 有些权限可以单独使用，有些可以与对象一起检查（例如，使用ContentItem的ViewContent权限）。
 * 
 * 在这里您将看到授权当前用户编辑Person内容项的示例。我们还将学习如何创建名为"Manage Persons"
 * 的自定义权限以及如何使用它。
 * 
 * 主要功能：
 * - 演示Orchard Core权限控制系统
 * - 展示内容项权限检查
 * - 演示自定义权限的使用
 * - 展示授权服务的最佳实践
 */

using Lombiq.TrainingDemo.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;
using OrchardCore.ContentManagement;
using OrchardCore.DisplayManagement.Notify;
using System.Threading.Tasks;

namespace Lombiq.TrainingDemo.Controllers;

/// <summary>
/// 授权控制器 - 演示Orchard Core权限控制和授权机制
/// 
/// 主要用途：
/// - 演示内容项权限检查
/// - 展示自定义权限的使用
/// - 演示授权服务的最佳实践
/// - 提供权限验证的示例
/// 
/// 使用场景：
/// - 检查用户是否有编辑特定内容项的权限
/// - 验证用户是否有管理人员的权限
/// - 演示权限检查的实际应用
/// - 展示授权失败的处理方式
/// 
/// 设计原因：
/// - 遵循Orchard Core的权限控制模式
/// - 提供标准化的权限检查方式
/// - 演示授权服务的使用方法
/// - 展示权限验证的最佳实践
/// 
/// 设计模式：
/// - 授权模式：使用IAuthorizationService进行权限检查
/// - 依赖注入模式：通过构造函数注入所需服务
/// - 内容管理模式：使用IContentManager管理内容项
/// - 通知模式：使用INotifier显示用户消息
/// </summary>
public sealed class AuthorizationController : Controller
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IContentManager _contentManager;
    private readonly INotifier _notifier;
    private readonly IHtmlLocalizer H;

    /// <summary>
    /// 构造函数 - 注入所需的服务依赖
    /// </summary>
    /// <param name="authorizationService">授权服务，用于权限检查</param>
    /// <param name="contentManager">内容管理器，用于创建和管理内容项</param>
    /// <param name="notifier">通知服务，用于显示用户消息</param>
    /// <param name="htmlLocalizer">HTML本地化器，用于多语言支持</param>
    public AuthorizationController(
        IAuthorizationService authorizationService,
        IContentManager contentManager,
        INotifier notifier,
        IHtmlLocalizer<AuthorizationController> htmlLocalizer)
    {
        _authorizationService = authorizationService;
        _contentManager = contentManager;
        _notifier = notifier;
        H = htmlLocalizer;
    }

    /// <summary>
    /// 检查用户是否可以编辑Person内容项
    /// 
    /// 功能说明：
    /// - 创建一个Person内容项用于测试（不会被持久化）
    /// - 检查用户是否有编辑该内容项的权限
    /// - 演示内容相关权限的检查方式
    /// - 展示权限检查的实际应用
    /// 
    /// 权限检查说明：
    /// - 当检查内容相关权限（ViewContent、EditContent、PublishContent等）时，
    ///   检查您自己的内容项（即所有者是您）和其他人的内容项之间存在差异
    /// - 当您是内容项的所有者时，将检查ViewOwnContent、EditOwnContent、PublishOwnContent等权限
    /// - 这是自动的，所以您不需要直接使用它们
    /// - 对于这个新创建的Person项目，所有者为null，所以将使用EditContent权限
    /// 
    /// 返回值：
    /// - 有权限：显示成功消息并重定向到首页
    /// - 无权限：返回401未授权状态
    /// </summary>
    /// <returns>重定向到首页或未授权状态</returns>
    // 在这里我们将创建一个Person内容项并检查用户是否有权限编辑它。检查您是否可以查看或编辑特定项目是很常见的
    // - 如果您使用内置URL如/Contents/Item/Display/{id}来查看内容项，也会发生这种情况。
    public async Task<IActionResult> CanEditPerson()
    {
        // 创建一个用于测试的内容项（不会被持久化）。
        var person = await _contentManager.NewAsync(ContentTypes.PersonPage);

        // 检查用户是否有权限编辑内容项。当您检查内容相关权限（ViewContent、EditContent、PublishContent等）时，
        // 检查您自己的内容项（即所有者是您）和其他人的内容项之间存在差异。当您是内容项的所有者时，
        // 将检查ViewOwnContent、EditOwnContent、PublishOwnContent等权限。这是自动的，所以您不需要直接使用它们。
        // 对于这个新创建的Person项目，所有者为null，所以将使用EditContent权限。
        if (!await _authorizationService.AuthorizeAsync(User, OrchardCore.Contents.CommonPermissions.EditContent, person))
        {
            // 使用此帮助器返回401状态码。虽然返回404（NotFound()）是防止枚举攻击的好做法。
            return Unauthorized();
        }

        // 为了保持演示简短，只显示关于成功授权的通知并返回到首页。
        await _notifier.InformationAsync(H["You are authorized to edit Person content items."]);

        return Redirect("~/");
    }

    // 下一站：Permissions/PersonPermissions

    /// <summary>
    /// 检查用户是否可以管理人员
    /// 
    /// 功能说明：
    /// - 检查用户是否有ManagePersons权限
    /// - 演示自定义权限的使用
    /// - 展示权限检查的简化方式
    /// 
    /// 权限说明：
    /// - 我们之前定义了一个ManagePersons权限，默认情况下会添加到Administrator用户
    /// - 如果当前用户没有Administrator角色，您可以在仪表板上添加它
    /// - 由于此权限可以在没有对象作为上下文的情况下检查，所以第三个参数被省略
    /// 
    /// 返回值：
    /// - 有权限：显示成功消息并重定向到首页
    /// - 无权限：返回401未授权状态
    /// </summary>
    /// <returns>重定向到首页或未授权状态</returns>
    public async Task<IActionResult> CanManagePersons()
    {
        // 我们之前定义了一个ManagePersons权限，默认情况下会添加到Administrator用户。
        // 如果当前用户没有Administrator角色，您可以在仪表板上添加它。
        // 由于此权限可以在没有对象作为上下文的情况下检查，所以第三个参数被省略。
        if (!await _authorizationService.AuthorizeAsync(User, PersonPermissions.ManagePersons))
        {
            return Unauthorized();
        }

        await _notifier.InformationAsync(H["You are authorized to manage persons."]);

        return Redirect("~/");
    }
}

// 训练部分结束：权限和授权

// 下一站：Controllers/AdminController
